from SeqDB import SeqDB
from Sequence import Sequence
from Element import Element

class GSP(object):

    def __init__(self,s,con,path):
        self.support = s
        self.db = SeqDB()
        self.result = []
        self.testpath=path
        self.confidence=con
        
    def getSequences(self):
        self.initialize()
        print "GSP 10 (1): ",self.l
        print "..........................."
        for i in range(0, len(self.l)):
            self.genCandidate()
            if not (len(self.c)>0):
                break
            print "GSP 17 :", len(self.c), "      dfs     ",self.c
            self.pruneC()
            print "GSP 19 :", len(self.c), "      dfs     ",self.c
            self.generateL()
            print "GSP 21 : ( ", i+2, " ) ", self.l
            self.addToResult(self.l)
            print "........................................"
        self.proceed(self.result)
        return self.result
                
    def initialize1(self):
        can ={}
        for s in self.db.getSeqs():
            for e in s.getElements():
                for i in e.getItems():
                    if can.has_key(i):
                        count =int(can.get(i))+1
                        can[i]=count
                    else:
                        can[i]=1
        self.l = []
        for i in can.keys():
            if int(can.get(i))>=self.support:
                e = Element([i])
                seq = Sequence(1)
                seq.addElement(e)
                self.l.append(seq)
        self.addToResult(self.l);
    
    def initialize(self):
        can ={}
        for s in self.db.getSeqs():
            for e in s.getElements():
                for i in e.getItems():
                    if can.has_key(i):
                        count =int(can.get(i))+1
                        can[i]=count
                    else:
                        can[i]=1
        self.l = []
        for i in can.keys():
            if int(can.get(i))>=self.support:
                e = Element([i])
                seq = Sequence(1)
                seq.addElement(e)
                self.l.append((seq,int(can.get(i))))
        self.addToResult(self.l);
        
    def genCandidate1(self):
        self.c=[]
        for i in range(0, len(self.l)):
            for j in range(i, len(self.l)):
                self.joinAndInsert(self.l[i],self.l[j])
                if not i==j:
                    self.joinAndInsert(self.l[j], self.l[i])
    
    def genCandidate(self):
        self.c=[]
        for i in range(0, len(self.l)):
            for j in range(i, len(self.l)):
                self.joinAndInsert(self.l[i][0],self.l[j][0])
                if not i==j:
                    self.joinAndInsert(self.l[j][0], self.l[i][0])

    def joinAndInsert(self,s1,s2):
        s=Sequence(1)
        st=Sequence(1)
        ef = (s1.getElement(0)).getWithoutFirstItem()
        ee = (s2.getElement(s2.size() - 1)).getWithoutLastItem()
        i=0
        j=0
        if ef.size()==0:
            i+=1
        while (i<s1.size() and j<s2.size()):
            e1=Element(1)
            e2=Element(1)
            if i==0:
                e1=ef
            else:
                e1=s1.getElement(i)
            
            if j==(s2.size()-1):
                e2=ee
            else:
                e2=s2.getElement(j)
            if not e1.equalsTo(e2):
                return
            i+=1
            j+=1
        s= Sequence(s1)
        (s.getElement(s.size()-1)).addItem((s2.getElement(s2.size()-1)).getLastItem())
        if s.notInSeqs(self.c,1):
            self.c.append(s)
        st=Sequence(s1)
        st.addElement(Element([s2.getElement(s2.size()-1).getLastItem()]))
        if st.notInSeqs(self.c,1):
            self.c.append(st)
        return
    
    def pruneC(self):
        
        for i in range(0, len(self.c)):
            if len(self.c)<i:
                s=self.c[i]
                for j in range(0, s.size()):
                    ce = s.getElement(j)
                    prune =0
                    if ce.size()==1:
                        s.removeElement(j)
                        if s.notInSeqs(self.l,2):
                            prune =1
                        s.insertElement(j,ce)
                    else:
                        for k in range(0, ce.size()):
                            item = ce.removeItem(k)
                            if s.notInSeqs(self.l,2):
                                prune =1
                            ce.addItem(item)
                    if prune==1:
                        self.c.pop(i)
                        i-=1
                        break
    
    def generateL1(self):
        self.l=[]
        for s in self.db.getSeqs():
            for seq in self.c:
                if seq.isSubsequenceOf(s):
                    seq.incrementSupport()
        for seq in self.c:
            if seq.getSupport()>=self.support:
                self.l.append(seq)
    def generateL(self):
        self.l=[]
        for s in self.db.getSeqs():
            for seq in self.c:
                if seq.isSubsequenceOf(s):
                    seq.incrementSupport()
        for seq in self.c:
            if seq.getSupport()>=self.support:
                self.l.append((seq,seq.getSupport()))
    def addToResult(self,l):
        for i in range(0, len(l)):
            self.result.append(l[i])
    
    def outputInput(self):
        print "Support ", self.support

    def proceed(self,freq_seqs):
        
        ruleset = []
        self.counter=0
        lth = 1
        length=set()
        for seq, support in freq_seqs:
            print seq, " - ", support
            lth=seq.size()
            if lth not in length:
                length.add(lth)
                self.counter+=1
            if lth>1:
                ruleset.append((seq.getElements()[:-1],seq.getElements()[-1:],support))
        holder = self.buildDataStruct(ruleset)
        self.GSPRecommender(holder) 
    #        if len(seq) > lth:
    #            counter += 1
    #            lth = len(seq)
    #        if len(seq) > 1:
    #            ruleset.append((seq[:-1],seq[-1:],support)) 
                    
        #holder = buildDataStruct(ruleset)
        
        #file = "F:\Uni\Final Year Project\Data\sessions6.csv"
        #file = "C:\Users\Gokul\Desktop\enaeseth-python-fp-growth-0.1.1-5-g5803128\enaeseth-python-fp-growth-5803128\samp.txt"
        #prefixspanRecommender(file, holder)    
    def buildDataStruct(self,seqs):
        holder = dict()
        ct = 0
        while ct <= self.counter:
            ct +=1
            holder[ct] = dict()
            
        for ant, con, sup in seqs:
            length = len(ant)
            seq = holder[length]
            antecedent = tuple(ant)
            consequent = tuple(con)
            try1=tuple([2])
            try2=tuple([2])
            if try1==antecedent:
                print "HI"
            if try2==antecedent:
                print "HI"
            if seq.has_key(antecedent):
                opt = seq.get(antecedent)
                opt[consequent] = sup
            else:
                opt = dict()
                opt[consequent] = sup
                seq[antecedent] = opt
                
        return holder
    def evaluate(self,recommendationSet,actual,average,count,correct):
        count+=1
        if actual in recommendationSet:
            average = calculateAccuracy(1,average,count)
            #print 'CORRECT'
            correct+=1
            return (average,count,correct)
        else:
            average=calculateAccuracy(0,average,count)
            #print 'INCORRECT'
            return (average,count,correct)
        
    def calculateAccuracy(correct,average,count):
            return ((int(count)-1)*float(average)+int(correct))*100/int(count)
    
                  
    def recommend(self,session, holder):
        sessionSet = tuple(session)
        length = len(session)
        if length > len(holder):
            return ""
        ruleSet = holder[length]
        if ruleSet.has_key(sessionSet):
            resultSet = ruleSet[sessionSet]
            recommendlist= []
            for key,item in resultSet.items():
                recommendlist.append(tuple(key))
            return recommendlist
        return ""
    
        
    def GSPRecommender(self,holder):
        
        file_iter = open(self.testpath, 'rU')
        count=0
        average=0
        total = 0
        correct =0
        print "Recommender : ", 1
        
        for line in file_iter:
            linex = line.strip().rstrip(',')
            elem = linex.split(',')
            iterator =0
            sessionList =[]
            if len(elem)>1:
                for item in elem:
                    iterator +=1
                    print "Recommender Iterator : ", iterator
                    if iterator==(len(elem)-1):
                        break
                    sessionList.append(item)
                    print "Recommender session : ", sessionList
                    recommendationList = self.recommend(sessionList, holder)
                    total+=1
                    print "Recommender recommendation : ", recommendationList
                    if not (len(recommendationList)<1):
                        result= self.evaluate(recommendationList, tuple([elem[iterator]]), average, count,correct)
                        average=result[0] 
                        count=result[1] 
                        correct=result[2]
                    else:
                        print "No valid recommendation"
        
        print "Average1 : ", average
        print "Total1 : ",total
        print "Count1 : ", count
        print "Correct1 : ", correct                
        if not (count == 0 or total == 0):                
            accuracy = float(correct)/float(count)
            coverage = float(count)/float(total)
            print "Average : ", average
            print "Total : ",total
            print "Count : ", count
            print "Correct : ", correct
            print "Accuracy : , %.3f" % (accuracy*100)
            print "Coverage : , %.3f"  % (coverage*100)
    
